function [Result, Model] = Ddavid_MLkLNN(SampledTrueLabelTraining, TrueLabelTesting, K, TrainingKNNList, TestingKNNList)

% [Result, Model] = Ddavid_MLkLNN(SampledTrueLabelTraining, TrueLabelTesting, K, TrainingKNNList, TestingKNNList)
%
% <Input>
% SampledTrueLabelTraining: [n*k], the value is {-1, 1}, the sampled labels
%                                  of the training data, k is the number of
%                                  labels
% TrueLabelTesting: [n'*k], the value is {-1, 1}, the real answer of labels
%                           of the testing data
% K: The K value of KLNN, K < n
% TrainingKNNList: [n*(n-1)], The KNN List between training points and
%                             other training points (for saving time)
% TestingKNNList: [n'*n], The KNN List between testing points and training
%                         points (for saving time)
%
% <Output>
% Result: [n*k], the predicted rank of testing data
% Model: [n*k], the model

TrainingSize = size(SampledTrueLabelTraining, 1);
TestingSize = size(TrueLabelTesting, 1);
LabelSize = size(SampledTrueLabelTraining, 2);

s = 1; % Laplace smoothing

% Training
%%% Computing the prior probabilities

TrainingLabeledSize = sum(SampledTrueLabelTraining == 1, 1);
TrainingPriorProb = (s + TrainingLabeledSize) / (2 * s + TrainingSize);

%%% Computing the posterior probabilities
%%%%% Computing the coverage posterior probabilities

%TrainingCoveragePostProb = ones(LabelSize, TrainingSize) * s;
TrainingCoveragePostProb1 = ones(LabelSize, TrainingSize) * s;
TrainingCoveragePostProb2 = ones(LabelSize, TrainingSize) * s;

for LabelCounter = 1:LabelSize
    for SizeCounter = 1:TrainingSize
        NeighborLabeledList = find((SampledTrueLabelTraining(TrainingKNNList(SizeCounter, 1:(TrainingSize - 1)), LabelCounter) == 1) == 1);
%        if(size(NeighborLabeledList) >= K)
%            Coverage = NeighborLabeledList(K);
%            if(SampledTrueLabelTraining(SizeCounter, LabelCounter) == 1)
%                TrainingCoveragePostProb(LabelCounter, Coverage) = TrainingCoveragePostProb(LabelCounter, Coverage) + 1;
%            end
        if(size(NeighborLabeledList) >= 1)
            Coverage = NeighborLabeledList(1);
            if(SampledTrueLabelTraining(SizeCounter, LabelCounter) == 1)
                TrainingCoveragePostProb1(LabelCounter, Coverage) = TrainingCoveragePostProb1(LabelCounter, Coverage) + 1;
            end
        end
        if(size(NeighborLabeledList) >= 2)
            Coverage = NeighborLabeledList(2);
            if(SampledTrueLabelTraining(SizeCounter, LabelCounter) == 1)
                TrainingCoveragePostProb2(LabelCounter, Coverage) = TrainingCoveragePostProb2(LabelCounter, Coverage) + 1;
            end
        end
    end
%    TrainingCoveragePostProb(LabelCounter, :) = TrainingCoveragePostProb(LabelCounter, :) / sum(TrainingCoveragePostProb(LabelCounter, :));
    TrainingCoveragePostProb1(LabelCounter, :) = TrainingCoveragePostProb1(LabelCounter, :) / sum(TrainingCoveragePostProb1(LabelCounter, :));
    TrainingCoveragePostProb2(LabelCounter, :) = TrainingCoveragePostProb2(LabelCounter, :) / sum(TrainingCoveragePostProb2(LabelCounter, :));
end

%%%%% Computing the final posterior probabilities

Model = zeros(TrainingSize, LabelSize);

for SizeCounter = 1:TrainingSize
%    Model(SizeCounter, :) = TrainingPriorProb .* TrainingCoveragePostProb(:, SizeCounter)';
    Model(SizeCounter, :) = TrainingPriorProb .* TrainingCoveragePostProb1(:, SizeCounter)' .* TrainingCoveragePostProb2(:, SizeCounter)';
end

% Testing

TestingCoverageList = zeros(TestingSize, LabelSize);

for LabelCounter = 1:LabelSize
    for SizeCounter = 1:TestingSize
        NeighborLabeledList = find((SampledTrueLabelTraining(TestingKNNList(SizeCounter, 1:TrainingSize), LabelCounter) == 1) == 1);
        if(size(NeighborLabeledList) >= K)
            TestingCoverageList(SizeCounter, LabelCounter) = NeighborLabeledList(K);
        else
            TestingCoverageList(SizeCounter, LabelCounter) = TrainingSize;
        end
    end
end

for SizeCounter = 1:TestingSize
    for LabelCounter = 1:LabelSize
        TestingCoverageList(SizeCounter, LabelCounter) = Model(TestingCoverageList(SizeCounter, LabelCounter), LabelCounter);
    end
end

[~, Result] = sort(TestingCoverageList, 2, 'descend');
